package binance

/**
 * API请求
**/

import (
	"encoding/json"
	"strings"
	"sync"
	"time"

	"github.com/astaxie/beego/logs"

	r "github.com/solos/requests"
)

const (
	BinanceDepthLimit = "1000"
	// BinanceDepthAPI   = "http://10.3.2.46:1080/api/v3/depth"
	BinanceDepthAPI = "https://api.binance.com/api/v3/depth"
)

type depthAPI struct {
	FirstUpdateID int64      `json:"lastUpdateId"`
	Bids          [][]string `json:"bids"`
	Asks          [][]string `json:"asks"`
}

type BinanceAPI struct {
	mu sync.Mutex
}

func NewBinanceApi() *BinanceAPI {
	return &BinanceAPI{}
}

// TODO 需要定期的更新全量的快照

// 请求获取数据
func (b *BinanceAPI) GetBinanceDepth(symbol, origin string) (data []byte) {

	b.mu.Lock()
	defer b.mu.Unlock()

	res, data := b.TryRequestTimes(symbol, BinanceDepthAPI, origin)
	if res && string(data) != "" {
		return data
	}
	return

}

func (h *BinanceAPI) TryRequestTimes(symbol, url, origin string) (res bool, resdata []byte) {

	defer func() { //必须要先声明defer，否则不能捕获到panic异常
		// fmt.Println("[*] Catch Request Error ....", symbol)
		if err := recover(); err != nil {
			// fmt.Println("[-] Request Failed", err, symbol) //这里的err其实就是panic传入的内容，"bug"
			res = false
			return
		}
	}()

	kwargs := r.M{}
	kwargs["timeout"] = 10

	// 设定请求头
	headers := map[string]string{
		"content-Type": "application/json",
	}
	// 请求数
	data := map[string]string{
		"symbol": strings.ToUpper(symbol),
		"limit":  BinanceDepthLimit,
	}

	// 实例化一个请求对象
	req := &r.Request{Args: kwargs}
	resp, err := req.MakeRequest("GET", url, r.Headers(headers), r.Params(data))
	if err != nil {
		logs.Debug("[api] 获取Token失败...", err)
		res = false
		return
	}

	dataMap := &depthAPI{}
	// 把后端返回的json字符串转换为[]byte
	dataBytes := []byte(resp.Content)
	// 反序列化成map
	err = json.Unmarshal(dataBytes, &dataMap) // 这里注意，一定要是传入指针类型
	if err != nil {
		logs.Debug("[binance-api] 反序列化成map失败...", err, string(dataBytes))
		res = false
		return
	}

	depthMap := make(map[string]interface{}, 3)

	bidsList := make([]map[string]string, len(dataMap.Bids))
	for i, bid := range dataMap.Bids {
		bidMap := make(map[string]string, 2)
		bidMap["amount"] = bid[1]
		bidMap["price"] = bid[0]
		bidsList[i] = bidMap
	}

	asksList := make([]map[string]string, len(dataMap.Asks))
	for i, ask := range dataMap.Asks {
		askMap := make(map[string]string, 2)
		askMap["amount"] = ask[1]
		askMap["price"] = ask[0]
		asksList[i] = askMap
	}

	if len(bidsList)*len(asksList) == 0 {
		res = false
		return
	}

	depthMap["bids"] = bidsList
	depthMap["asks"] = asksList
	depthMap["ts"] = time.Now().UnixNano() / 1e6
	depthMap["firstUpdateId"] = dataMap.FirstUpdateID
	depthMap["market"] = origin

	resdata, _ = json.Marshal(depthMap)
	res = true
	return
}
